﻿package com.oaxoa.fx
{
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.utils.*;

    public class Lightning extends Sprite
    {
        private var _childrenProbabilityDecay:Number = 0;
        public var multi2:Number;
        public var len:Number;
        private var soff:Number;
        private var bbd:BitmapData;
        public var _steps:uint;
        public var startX:Number;
        public var startY:Number;
        private var _childrenLengthDecay:Number = 0;
        private var boffs:Array;
        private var boffx:Number;
        private var boffy:Number;
        public var lifeSpan:Number;
        public var _isVisible:Boolean = true;
        public var _color:uint;
        public var _childrenSmoothPercentage:uint;
        private var tx:Number;
        public var childrenSmooth:Sprite;
        private var dx:Number;
        private var ty:Number;
        private var dy:Number;
        private var _maxLengthVary:Number = 0;
        private var _wavelength:Number = 0.3;
        private var initialized:Boolean = false;
        private var angle:Number;
        private var _thicknessDecay:Number;
        public var endY:Number;
        private var _childrenLifeSpanMax:Number = 0;
        public var endX:Number;
        private var _amplitude:Number = 0.5;
        private var generation:uint;
        private var calculatedSpeed:Number;
        public var multi:Number;
        private var position:Number = 0;
        public var _smoothPercentage:uint = 50;
        private var _speed:Number = 1;
        public var alphaFadeType:String;
        private var _childrenMaxGenerations:uint = 3;
        public var parentInstance:Lightning;
        public var thicknessFadeType:String;
        private const SMOOTH_COLOR:uint = 8421504;
        public var _alphaFade:Boolean = true;
        private var calculatedWavelength:Number;
        private var _childrenAngleVariation:Number = 60;
        private var _childrenMaxCount:uint = 4;
        public var childrenArray:Array;
        private var glow:GlowFilter;
        private var lifeTimer:Timer;
        private var holder:Sprite;
        public var stepEvery:Number;
        private var _childrenMaxCountDecay:Number = 0.5;
        public var smooth:Sprite;
        private var boff:Number;
        private var _childrenLifeSpanMin:Number = 0;
        private var absolutePosition:Number = 1;
        private var _childrenDetachedEnd:Boolean = false;
        private var soffs:Array;
        private var soffx:Number;
        private var soffy:Number;
        private var seed1:uint;
        private var seed2:uint;
        private var _maxLength:Number = 0;
        private var sbd:BitmapData;
        private var _childrenProbability:Number = 0.025;
        private var _thickness:Number;

        public function Lightning(param1:uint = 16777215, param2:Number = 2, param3:uint = 0)
        {
            childrenArray = [];
            _smoothPercentage = 50;
            _childrenMaxGenerations = 3;
            _childrenProbability = 0.025;
            _childrenProbabilityDecay = 0;
            _childrenMaxCount = 4;
            _childrenMaxCountDecay = 0.5;
            _childrenLengthDecay = 0;
            _childrenAngleVariation = 60;
            _childrenLifeSpanMin = 0;
            _childrenLifeSpanMax = 0;
            _childrenDetachedEnd = false;
            _maxLength = 0;
            _maxLengthVary = 0;
            _isVisible = true;
            _alphaFade = true;
            initialized = false;
            _wavelength = 0.3;
            _amplitude = 0.5;
            _speed = 1;
            position = 0;
            absolutePosition = 1;
            mouseEnabled = false;
            _color = param1;
            _thickness = param2;
            alphaFadeType = LightningFadeType.GENERATION;
            thicknessFadeType = LightningFadeType.NONE;
            generation = param3;
            if (generation == 0)
            {
                init();
            }
            return;
        }// end function

        public function set childrenLengthDecay(param1:Number) : void
        {
            if (param1 > 1)
            {
                param1 = 1;
            }
            else if (param1 < 0)
            {
                param1 = 0;
            }
            _childrenLengthDecay = param1;
            return;
        }// end function

        public function set childrenSmoothPercentage(param1:Number) : void
        {
            var _loc_2:Matrix = null;
            var _loc_3:uint = 0;
            _childrenSmoothPercentage = param1;
            _loc_2 = new Matrix();
            _loc_2.createGradientBox(steps, 1);
            _loc_3 = _childrenSmoothPercentage / 100 * 128;
            childrenSmooth.graphics.clear();
            childrenSmooth.graphics.beginGradientFill("linear", [SMOOTH_COLOR, SMOOTH_COLOR, SMOOTH_COLOR, SMOOTH_COLOR], [1, 0, 0, 1], [0, _loc_3, 255 - _loc_3, 255], _loc_2);
            childrenSmooth.graphics.drawRect(0, 0, steps, 1);
            childrenSmooth.graphics.endFill();
            return;
        }// end function

        public function set wavelength(param1:Number) : void
        {
            var _loc_2:Object = null;
            _wavelength = param1;
            for each (_loc_2 in childrenArray)
            {
                
                _loc_2.instance.wavelength = param1;
            }
            return;
        }// end function

        public function get childrenMaxGenerations() : uint
        {
            return _childrenMaxGenerations;
        }// end function

        public function set childrenMaxCount(param1:uint) : void
        {
            _childrenMaxCount = param1;
            killSurplus();
            return;
        }// end function

        public function set steps(param1:uint) : void
        {
            if (param1 < 2)
            {
                param1 = 2;
            }
            if (param1 > 2880)
            {
                param1 = 2880;
            }
            _steps = param1;
            sbd = new BitmapData(_steps, 1, false);
            bbd = new BitmapData(_steps, 1, false);
            if (generation == 0)
            {
                smoothPercentage = smoothPercentage;
            }
            return;
        }// end function

        public function get childrenAngleVariation() : Number
        {
            return _childrenAngleVariation;
        }// end function

        public function get speed() : Number
        {
            return _speed;
        }// end function

        public function killAllChildren() : void
        {
            var _loc_1:Lightning = null;
            while (childrenArray.length > 0)
            {
                
                _loc_1 = childrenArray[0].instance;
                _loc_1.kill();
            }
            return;
        }// end function

        public function get amplitude() : Number
        {
            return _amplitude;
        }// end function

        public function get childrenDetachedEnd() : Boolean
        {
            return _childrenDetachedEnd;
        }// end function

        public function set childrenMaxGenerations(param1:uint) : void
        {
            _childrenMaxGenerations = param1;
            killSurplus();
            return;
        }// end function

        public function get childrenLifeSpanMin() : Number
        {
            return _childrenLifeSpanMin;
        }// end function

        private function onTimer(event:TimerEvent) : void
        {
            kill();
            return;
        }// end function

        public function generateChild(param1:uint = 1, param2:Boolean = false) : void
        {
            var _loc_3:uint = 0;
            var _loc_4:uint = 0;
            var _loc_5:uint = 0;
            var _loc_6:uint = 0;
            var _loc_7:Number = NaN;
            var _loc_8:Lightning = null;
            if (generation < childrenMaxGenerations && childrenArray.length < childrenMaxCount)
            {
                _loc_3 = steps * childrenLengthDecay;
                if (_loc_3 >= 2)
                {
                    _loc_4 = 0;
                    while (_loc_4 < param1)
                    {
                        
                        _loc_5 = Math.random() * steps;
                        _loc_6 = Math.random() * steps;
                        while (_loc_6 == _loc_5)
                        {
                            
                            _loc_6 = Math.random() * steps;
                        }
                        _loc_7 = Math.random() * childrenAngleVariation - childrenAngleVariation / 2;
                        _loc_8 = new Lightning(color, thickness, (generation + 1));
                        _loc_8.parentInstance = this;
                        _loc_8.lifeSpan = Math.random() * (childrenLifeSpanMax - childrenLifeSpanMin) + childrenLifeSpanMin;
                        _loc_8.position = 1 - _loc_5 / steps;
                        _loc_8.absolutePosition = absolutePosition * _loc_8.position;
                        _loc_8.alphaFadeType = alphaFadeType;
                        _loc_8.thicknessFadeType = thicknessFadeType;
                        if (alphaFadeType == LightningFadeType.GENERATION)
                        {
                            _loc_8.alpha = 1 - 1 / (childrenMaxGenerations + 1) * _loc_8.generation;
                        }
                        if (thicknessFadeType == LightningFadeType.GENERATION)
                        {
                            _loc_8.thickness = thickness - thickness / (childrenMaxGenerations + 1) * _loc_8.generation;
                        }
                        _loc_8.childrenMaxGenerations = childrenMaxGenerations;
                        _loc_8.childrenMaxCount = childrenMaxCount * (1 - childrenMaxCountDecay);
                        _loc_8.childrenProbability = childrenProbability * (1 - childrenProbabilityDecay);
                        _loc_8.childrenProbabilityDecay = childrenProbabilityDecay;
                        _loc_8.childrenLengthDecay = childrenLengthDecay;
                        _loc_8.childrenDetachedEnd = childrenDetachedEnd;
                        _loc_8.wavelength = wavelength;
                        _loc_8.amplitude = amplitude;
                        _loc_8.speed = speed;
                        _loc_8.init();
                        childrenArray.push({instance:_loc_8, startStep:_loc_5, endStep:_loc_6, detachedEnd:childrenDetachedEnd, childAngle:_loc_7});
                        addChild(_loc_8);
                        _loc_8.steps = steps * (1 - childrenLengthDecay);
                        if (param2)
                        {
                            _loc_8.generateChild(param1, true);
                        }
                        _loc_4 = _loc_4 + 1;
                    }
                }
            }
            return;
        }// end function

        public function get childrenProbabilityDecay() : Number
        {
            return _childrenProbabilityDecay;
        }// end function

        public function killSurplus() : void
        {
            var _loc_1:Lightning = null;
            while (childrenArray.length > childrenMaxCount)
            {
                
                _loc_1 = childrenArray[(childrenArray.length - 1)].instance;
                _loc_1.kill();
            }
            return;
        }// end function

        public function get thicknessDecay() : Number
        {
            return _thicknessDecay;
        }// end function

        public function get childrenMaxCountDecay() : Number
        {
            return _childrenMaxCountDecay;
        }// end function

        public function set speed(param1:Number) : void
        {
            var _loc_2:Object = null;
            _speed = param1;
            for each (_loc_2 in childrenArray)
            {
                
                _loc_2.instance.speed = param1;
            }
            return;
        }// end function

        public function get maxLengthVary() : Number
        {
            return _maxLengthVary;
        }// end function

        public function set color(param1:uint) : void
        {
            var _loc_2:Object = null;
            _color = param1;
            glow.color = param1;
            holder.filters = [glow];
            for each (_loc_2 in childrenArray)
            {
                
                _loc_2.instance.color = param1;
            }
            return;
        }// end function

        public function update() : void
        {
            var _loc_1:Number = NaN;
            var _loc_2:Object = null;
            var _loc_3:Matrix = null;
            var _loc_4:Number = NaN;
            if (initialized)
            {
                dx = endX - startX;
                dy = endY - startY;
                len = Math.sqrt(dx * dx + dy * dy);
                soffs[0].x = soffs[0].x + steps / 100 * speed;
                soffs[0].y = soffs[0].y + steps / 100 * speed;
                sbd.perlinNoise(steps / 20, steps / 20, 1, seed1, false, true, 7, true, soffs);
                calculatedWavelength = steps * wavelength;
                calculatedSpeed = calculatedWavelength * 0.1 * speed;
                boffs[0].x = boffs[0].x - calculatedSpeed;
                boffs[0].y = boffs[0].y + calculatedSpeed;
                bbd.perlinNoise(calculatedWavelength, calculatedWavelength, 1, seed2, false, true, 7, true, boffs);
                if (smoothPercentage > 0)
                {
                    _loc_3 = new Matrix();
                    _loc_3.scale(steps / smooth.width, 1);
                    bbd.draw(smooth, _loc_3);
                }
                if (parentInstance != null)
                {
                    isVisible = parentInstance.isVisible;
                }
                else if (maxLength == 0)
                {
                    isVisible = true;
                }
                else
                {
                    if (len <= maxLength)
                    {
                        _loc_4 = 1;
                    }
                    else if (len > maxLength + maxLengthVary)
                    {
                        _loc_4 = 0;
                    }
                    else
                    {
                        _loc_4 = 1 - (len - maxLength) / maxLengthVary;
                    }
                    isVisible = Math.random() < _loc_4 ? (true) : (false);
                }
                _loc_1 = Math.random();
                if (_loc_1 < childrenProbability)
                {
                    generateChild();
                }
                if (isVisible)
                {
                    render();
                }
                for each (_loc_2 in childrenArray)
                {
                    
                    _loc_2.instance.update();
                }
            }
            return;
        }// end function

        public function set childrenAngleVariation(param1:Number) : void
        {
            var _loc_2:Object = null;
            _childrenAngleVariation = param1;
            for each (_loc_2 in childrenArray)
            {
                
                _loc_2.childAngle = Math.random() * param1 - param1 / 2;
                _loc_2.instance.childrenAngleVariation = param1;
            }
            return;
        }// end function

        public function get childrenProbability() : Number
        {
            return _childrenProbability;
        }// end function

        public function get smoothPercentage() : Number
        {
            return _smoothPercentage;
        }// end function

        public function set thickness(param1:Number) : void
        {
            if (param1 < 0)
            {
                param1 = 0;
            }
            _thickness = param1;
            return;
        }// end function

        private function randomizeSeeds() : void
        {
            seed1 = Math.random() * 100;
            seed2 = Math.random() * 100;
            return;
        }// end function

        public function get childrenLengthDecay() : Number
        {
            return _childrenLengthDecay;
        }// end function

        public function set maxLength(param1:Number) : void
        {
            _maxLength = param1;
            return;
        }// end function

        public function set amplitude(param1:Number) : void
        {
            var _loc_2:Object = null;
            _amplitude = param1;
            for each (_loc_2 in childrenArray)
            {
                
                _loc_2.instance.amplitude = param1;
            }
            return;
        }// end function

        public function get childrenSmoothPercentage() : Number
        {
            return _childrenSmoothPercentage;
        }// end function

        private function init() : void
        {
            randomizeSeeds();
            if (lifeSpan > 0)
            {
                startLifeTimer();
            }
            multi2 = 0.03;
            holder = new Sprite();
            holder.mouseEnabled = false;
            startX = 50;
            startY = 200;
            endX = 50;
            endY = 600;
            stepEvery = 4;
            _steps = 50;
            sbd = new BitmapData(_steps, 1, false);
            bbd = new BitmapData(_steps, 1, false);
            soffs = [new Point(0, 0), new Point(0, 0)];
            boffs = [new Point(0, 0), new Point(0, 0)];
            if (generation == 0)
            {
                smooth = new Sprite();
                childrenSmooth = new Sprite();
                smoothPercentage = 50;
                childrenSmoothPercentage = 50;
            }
            else
            {
                var _loc_1:* = parentInstance.childrenSmooth;
                childrenSmooth = parentInstance.childrenSmooth;
                smooth = _loc_1;
            }
            steps = 100;
            childrenLengthDecay = 0.5;
            addChild(holder);
            initialized = true;
            return;
        }// end function

        public function set childrenDetachedEnd(param1:Boolean) : void
        {
            _childrenDetachedEnd = param1;
            return;
        }// end function

        public function get wavelength() : Number
        {
            return _wavelength;
        }// end function

        public function get steps() : uint
        {
            return _steps;
        }// end function

        public function get childrenMaxCount() : uint
        {
            return _childrenMaxCount;
        }// end function

        public function set childrenLifeSpanMin(param1:Number) : void
        {
            _childrenLifeSpanMin = param1;
            return;
        }// end function

        public function set childrenLifeSpanMax(param1:Number) : void
        {
            _childrenLifeSpanMax = param1;
            return;
        }// end function

        public function set thicknessDecay(param1:Number) : void
        {
            if (param1 > 1)
            {
                param1 = 1;
            }
            else if (param1 < 0)
            {
                param1 = 0;
            }
            _thicknessDecay = param1;
            return;
        }// end function

        public function set childrenProbabilityDecay(param1:Number) : void
        {
            if (param1 > 1)
            {
                param1 = 1;
            }
            else if (param1 < 0)
            {
                param1 = 0;
            }
            _childrenProbabilityDecay = param1;
            return;
        }// end function

        public function startLifeTimer() : void
        {
            lifeTimer = new Timer(lifeSpan * 1000, 1);
            lifeTimer.start();
            lifeTimer.addEventListener(TimerEvent.TIMER, onTimer);
            return;
        }// end function

        public function kill() : void
        {
            var _loc_1:uint = 0;
            var _loc_2:Lightning = null;
            var _loc_3:Object = null;
            killAllChildren();
            if (lifeTimer)
            {
                lifeTimer.removeEventListener(TimerEvent.TIMER, kill);
                lifeTimer.stop();
            }
            if (parentInstance != null)
            {
                _loc_1 = 0;
                _loc_2 = this.parent as Lightning;
                for each (_loc_3 in _loc_2.childrenArray)
                {
                    
                    if (_loc_3.instance == this)
                    {
                        _loc_2.childrenArray.splice(_loc_1, 1);
                    }
                    _loc_1 = _loc_1 + 1;
                }
            }
            this.parent.removeChild(this);
            delete this[this];
            return;
        }// end function

        public function set childrenMaxCountDecay(param1:Number) : void
        {
            if (param1 > 1)
            {
                param1 = 1;
            }
            else if (param1 < 0)
            {
                param1 = 0;
            }
            _childrenMaxCountDecay = param1;
            return;
        }// end function

        public function get maxLength() : Number
        {
            return _maxLength;
        }// end function

        public function set childrenProbability(param1:Number) : void
        {
            if (param1 > 1)
            {
                param1 = 1;
            }
            else if (param1 < 0)
            {
                param1 = 0;
            }
            _childrenProbability = param1;
            return;
        }// end function

        public function get thickness() : Number
        {
            return _thickness;
        }// end function

        public function set maxLengthVary(param1:Number) : void
        {
            _maxLengthVary = param1;
            return;
        }// end function

        public function get color() : uint
        {
            return _color;
        }// end function

        public function render() : void
        {
            var _loc_1:Object = null;
            var _loc_2:uint = 0;
            var _loc_3:Number = NaN;
            var _loc_4:Number = NaN;
            var _loc_5:Number = NaN;
            var _loc_6:Number = NaN;
            var _loc_7:Number = NaN;
            holder.graphics.clear();
            holder.graphics.lineStyle(thickness, _color);
            angle = Math.atan2(endY - startY, endX - startX);
            _loc_2 = 0;
            while (_loc_2 < steps)
            {
                
                _loc_3 = 1 / steps * (steps - _loc_2);
                _loc_4 = 1;
                _loc_5 = thickness;
                if (alphaFadeType == LightningFadeType.TIP_TO_END)
                {
                    _loc_4 = absolutePosition * _loc_3;
                }
                if (thicknessFadeType == LightningFadeType.TIP_TO_END)
                {
                    _loc_5 = thickness * (absolutePosition * _loc_3);
                }
                if (alphaFadeType == LightningFadeType.TIP_TO_END || thicknessFadeType == LightningFadeType.TIP_TO_END)
                {
                    holder.graphics.lineStyle(int(_loc_5), _color, _loc_4);
                }
                soff = (sbd.getPixel(_loc_2, 0) - 8421504) / 16777215 * len * multi2;
                soffx = Math.sin(angle) * soff;
                soffy = Math.cos(angle) * soff;
                boff = (bbd.getPixel(_loc_2, 0) - 8421504) / 16777215 * len * amplitude;
                boffx = Math.sin(angle) * boff;
                boffy = Math.cos(angle) * boff;
                tx = startX + dx / (steps - 1) * _loc_2 + soffx + boffx;
                ty = startY + dy / (steps - 1) * _loc_2 - soffy - boffy;
                if (_loc_2 == 0)
                {
                    holder.graphics.moveTo(tx, ty);
                }
                holder.graphics.lineTo(tx, ty);
                for each (_loc_1 in childrenArray)
                {
                    
                    if (_loc_1.startStep == _loc_2)
                    {
                        _loc_1.instance.startX = tx;
                        _loc_1.instance.startY = ty;
                    }
                    if (_loc_1.detachedEnd)
                    {
                        _loc_6 = angle + _loc_1.childAngle / 180 * Math.PI;
                        _loc_7 = len * childrenLengthDecay;
                        _loc_1.instance.endX = _loc_1.instance.startX + Math.cos(_loc_6) * _loc_7;
                        _loc_1.instance.endY = _loc_1.instance.startY + Math.sin(_loc_6) * _loc_7;
                        continue;
                    }
                    if (_loc_1.endStep == _loc_2)
                    {
                        _loc_1.instance.endX = tx;
                        _loc_1.instance.endY = ty;
                    }
                }
                _loc_2 = _loc_2 + 1;
            }
            return;
        }// end function

        public function get childrenLifeSpanMax() : Number
        {
            return _childrenLifeSpanMax;
        }// end function

        public function set smoothPercentage(param1:Number) : void
        {
            var _loc_2:Matrix = null;
            var _loc_3:uint = 0;
            if (smooth)
            {
                _smoothPercentage = param1;
                _loc_2 = new Matrix();
                _loc_2.createGradientBox(steps, 1);
                _loc_3 = _smoothPercentage / 100 * 128;
                smooth.graphics.clear();
                smooth.graphics.beginGradientFill("linear", [SMOOTH_COLOR, SMOOTH_COLOR, SMOOTH_COLOR, SMOOTH_COLOR], [1, 0, 0, 1], [0, _loc_3, 255 - _loc_3, 255], _loc_2);
                smooth.graphics.drawRect(0, 0, steps, 1);
                smooth.graphics.endFill();
            }
            return;
        }// end function

        public function get isVisible() : Boolean
        {
            return _isVisible;
        }// end function

        public function set isVisible(param1:Boolean) : void
        {
            var _loc_2:* = param1;
            visible = param1;
            _isVisible = _loc_2;
            return;
        }// end function

    }
}
